/*
The original code to manage and animate MD2 models was modified to allow non-repeating
animations as well as a callback registration function to allow some action to take
place upon termination of a non-repeating animation.


 *  Object3D.cpp
 *  MD2 File Loading
 *
 *  Created by Seth Willits on 9/11/04.
 *  Copyright 2004 Freak Software. All rights reserved.
 *
 */

#include "Object3D.h"
#include "MovableObject.h"


///////////////////////////////////////////////////////////////////////////
//	Object States
//	
///////////////////////////////////////////////////////////////////////////


Object3DState kObjectStates[15] =  {{  0,  39},	{ 74,  95},	{113, 122},	{123, 135},
									{40,  46},	{ 67,  73},	{ 47,  60},	{ 61,  66},
									{136, 154},	{155, 161},	{162, 169},	{170, 177},
									{178, 185},	{186, 190},	{191, 197}};



///////////////////////////////////////////////////////////////////////////
//	Constructor 
//	
///////////////////////////////////////////////////////////////////////////

Object3D::Object3D(short pMaxModelCount, MovableObject* parent)
{
	repeat = false;
	//finishEvent = onAnimationFinish;
	object = parent;

	// Allocate Pointers for MD2 Models
	mModels = (MD2Model**) calloc(sizeof(MD2Model*), pMaxModelCount);
	
	// Set Max Model Count
	mMaxModelCount = pMaxModelCount;
	mModelCount = 0;
	
	// Set Frames and States
	SetState(kIdle1, true);
}



///////////////////////////////////////////////////////////////////////////
//	Destructor 
//	
///////////////////////////////////////////////////////////////////////////

Object3D::~Object3D()
{
	for (int i = 0; i < mModelCount; i++) {
		delete mModels[i];
	}
}



///////////////////////////////////////////////////////////////////////////
//	LoadModel - 
//	
///////////////////////////////////////////////////////////////////////////

bool Object3D::LoadModel(char * pModelFile, char * pSkinFile)
{
	MD2Model * newModel;
	bool result;
	
	
	// Don't Load More than mModelCount Models
	if (mModelCount == mMaxModelCount)
		return false;
	
	// Load New MD2 Model
	newModel = new MD2Model;
	result = newModel->Load(pModelFile, pSkinFile);
	
	// Save or Delete Model
	if (result) {
		mModels[mModelCount] = newModel;
		mModelCount += 1;
		
	} else
		delete newModel;
	
	return result;
}



///////////////////////////////////////////////////////////////////////////
//	Draw - 
//	
///////////////////////////////////////////////////////////////////////////

void Object3D::Draw()
{
	// Loop through Models and Draw 
	for (int i = 0; i < mModelCount; i++) {
		mModels[i]->Draw(mCurrentFrame, mNextFrame, mInterpolation);
	}
}


///////////////////////////////////////////////////////////////////////////
//	SetState - 
//	
///////////////////////////////////////////////////////////////////////////

void Object3D::SetState(int pState, bool r)
{
	repeat = r;
	mCurrentStateIndex = mNextStateIndex = pState;
	mCurrentState = mNextState = kObjectStates[pState];
	mCurrentFrame = mCurrentState.Start;
	mNextFrame = mCurrentState.Start + 1;
	mInterpolation = 0.0f;
}



///////////////////////////////////////////////////////////////////////////
//	ChangeState - 
//	
///////////////////////////////////////////////////////////////////////////

void Object3D::ChangeState(int pState)
{
	mNextStateIndex = pState;
	mNextState = kObjectStates[pState];
	mNextFrame = mNextState.Start;
	mInterpolation = 0.0f;
}



///////////////////////////////////////////////////////////////////////////
//	GetCurrentState - 
//	
///////////////////////////////////////////////////////////////////////////

int Object3D::GetCurrentState()
{
	return mCurrentStateIndex;
}



///////////////////////////////////////////////////////////////////////////
//	GetNextState - 
//	
///////////////////////////////////////////////////////////////////////////

int Object3D::GetNextState()
{
	return mNextStateIndex;
}



///////////////////////////////////////////////////////////////////////////
//	Update - 
//	
///////////////////////////////////////////////////////////////////////////

void Object3D::Update()
{
	// Increase Interpolation
	mInterpolation += kO3DFrameStep;
	
	// If Interpolation overflowed, go to next frame
	if (mInterpolation > 1.0) {
		
		
		// Next frame is in the same state
		if (mCurrentState.Start == mNextState.Start) {
			mCurrentFrame = mNextFrame;
			mNextFrame = mCurrentFrame + 1;
		
		// Next Frame is in another state
		} else {
			mCurrentFrame = mNextState.Start;
			mNextFrame = mCurrentFrame + 1;
			mCurrentState = mNextState;
		}
		
		
		// Check frame bounds
		if (mCurrentFrame == mCurrentState.End || mNextFrame == mCurrentState.End)
		{
			
			if (repeat)
			{
				mNextFrame = mCurrentState.Start;
			}else{
				mNextFrame = mCurrentFrame;
				//(*finishEvent)(mCurrentStateIndex, this);
				object->onAnimationFinish(mCurrentStateIndex);
			}
		}
		
		if (mCurrentFrame > mCurrentState.End)
			mCurrentFrame = mCurrentState.End;
		
		
		// Reset the Interpolation
		mInterpolation = 0.0;
	}
}




///////////////////////////////////////////////////////////////////////////
//	 - 
//	
///////////////////////////////////////////////////////////////////////////

